package com.atguigu.mq.config;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.concurrent.locks.Lock;

// 监听消费消息
@Component
@Slf4j
public class MyMessageListener {
    public static final String EXCHANGE_DIRECT = "exchange.direct.order";
    public static final String ROUTING_KEY = "order";
    public static final String QUEUE_NAME  = "queue.order";


    @RabbitListener(
            bindings = @QueueBinding(
                    exchange = @Exchange(value = EXCHANGE_DIRECT, type = "direct"),
                    value = @Queue(value = QUEUE_NAME),
                    key = {ROUTING_KEY}
            )
    )
    public void processMessage(String dataString, Message message, Channel channel)  {

        // 设置消息持久化
        // message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.fromInt(2));


        // 获取消息的标识符 deliveryTag
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            // 业务
            //Thread.sleep(1000);
            log.info("获取到队列消息: " + dataString);
            // int i = 1 / 0; 模拟异常
            /**
             * 确认消息处理成功
             * 当消息处理服务确认消息已被成功处理时，调用此方法发送确认信息
             * 这个确认操作是针对特定消息的，通过deliveryTag来标识该消息
             * 参数:
             *   deliveryTag - 消息的唯一标识符，用于确认具体是哪条消息被处理
             *   false - 表示确认是针对单个消息的，而不是批量确认
             * 此方法的调用标志着消息处理的完成，并告知消息队列可以安全地删除该消息
             */
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            e.printStackTrace();
            if (!message.getMessageProperties().getRedelivered()) { // 判断消息是否被投递过
                try {
                    // 拒绝确认消息，但不重新排队，且请求重新发送
                    // 拒绝确认消息，但将其重新放入队列以待再次处理
                    channel.basicNack(deliveryTag, false, true);
                    log.error("消息处理失败，消息重新投递中...");
                } catch (IOException ex) {
                    e.printStackTrace();
                }
            } else {
                try {
                    /**
                     * 拒绝处理当前消息
                     * 当处理消息失败或不希望确认消息时调用此方法
                     *
                     * @param deliveryTag 消息的投递标签，用于标识特定的消息
                     * @param requeue     false表示拒绝消息并且不重新入队，true表示拒绝消息但重新入队
                     *                   设置为false意味着消息将被丢弃或发送到死信队列（如果配置了）
                     */
                    channel.basicReject(deliveryTag, false);
                    log.error("消息处理失败，消息已拒绝...");
                } catch (IOException ex) {
                    e.printStackTrace();
                }
            }
        }
    }
}
